// Copyright (C) 2010, Scott W. Dunlop <swdunlop@gmail.com>
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define NOSPEX_IMPL_SOURCE // Indicates that this is an implementation file.


#include "nospex.h"
#include <stdlib.h>

void nx_graph_dispatch_pointer( nx_graph_p graph, double x, double y ){
    double radius = NX_NODE_RADIUS / graph->pitch;

    graph->ptr_x = x;
    graph->ptr_y = y;
    
    // Don't jerk the current node out of the user's hand.
    if(( graph->ptr_down )&&( graph->ptr_elem != NULL )) return;

    nx_element_p e = nx_find_element_at( graph, x, y );

    if( graph->ptr_elem == e ) return;
    if( graph->ptr_elem != NULL ){
        nx_signal_resource( 
            (nx_resource_p)graph->ptr_elem, NX_ELEMENT_LEAVE_EVT, x, y 
        );
    }; 
            
    if( e != NULL ){
        nx_signal_resource( (nx_resource_p)e, NX_ELEMENT_ENTER_EVT, x, y );
    };

    graph->ptr_elem = e;
}

void nx_graph_redispatch_pointer( nx_graph_p graph ){
    if( graph->ptr_x == -100.0 ) return;
    nx_graph_dispatch_pointer( graph, graph->ptr_x, graph->ptr_y );
}

void nx_graph_handle_exposure( nx_graph_p graph, cairo_t* cr ){
    nx_draw_graph( graph, cr );
    cairo_destroy( cr );
}

void nx_graph_handle_resize( 
    nx_graph_p graph, double width, double height
){
    //TODO: Collapse with nx_resize_graph ?
    nx_resize_graph( graph, width, height );
}

void nx_graph_handle_button_press( nx_graph_p graph, double x, double y ){
    if( ! graph->ptr_down ){
        graph->ptr_down = nx_system_clock( );
    };

    nx_graph_dispatch_pointer( graph, x, y );
}

void nx_graph_handle_button_release( nx_graph_p graph, double x, double y ){
    if( ! graph->ptr_down ) return; // Paranoia mode.
    nx_time ptr_dur = nx_system_clock( ) - graph->ptr_down;
    
    if( ptr_dur < 100 ){
        //TODO: Adapt to handle ptr blip. 
        if( graph->ptr_elem == NULL ){
            nx_signal_graph( graph, NX_GRAPH_CLICK_EVT, x, y );
        }else{
            nx_signal_resource( (nx_resource_p)graph->ptr_elem, NX_ELEMENT_CLICK_EVT, x, y );
        };
    };
    
    graph->ptr_down = 0;
    nx_graph_dispatch_pointer( graph, x, y );
}

void nx_graph_handle_motion( nx_graph_p graph, double x, double y ){
    if( ! graph->ptr_down ){
        nx_graph_dispatch_pointer( graph, x, y );
    }else{
        if( (nx_system_clock( ) - graph->ptr_down) > 100 ){
            if( graph->ptr_elem != NULL ){
                //TODO: Determine if we need to do playfield drags?
                nx_signal_resource( 
                    (nx_resource_p)graph->ptr_elem, NX_ELEMENT_DRAG_EVT, x, y 
                );
            };
        };
        graph->ptr_x = x; graph->ptr_y = y;
    };
}

